package com.kwin.rpcclient.scan;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;

import com.kwin.rpccommon.annotation.RpcClient;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import lombok.extern.slf4j.Slf4j;

/**
 * @author : wangkai
 * @version V1.0
 * @Package com.kwin.rpc.config.rpc
 * @Description:
 * @date 2021年06月22日 15:13
 **/
@Slf4j
public class ClassPathRpcScanner extends ClassPathBeanDefinitionScanner{
    
    private RpcFactoryBean<?> rpcFactoryBean = new RpcFactoryBean<Object>();
    
    private Class<? extends Annotation> annotationClass;
    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
        this.annotationClass = annotationClass;
    }
    
    public void setRpcFactoryBean(RpcFactoryBean<?> rpcFactoryBean) {
        this.rpcFactoryBean = rpcFactoryBean;
    }
    
    public ClassPathRpcScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
    
    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        
        if (beanDefinitions.isEmpty()) {
            log.warn("No RPC mapper was found in  {} package. Please check your configuration.", Arrays.toString(basePackages));
        } else {
            processBeanDefinitions(beanDefinitions);
        }
        
        return beanDefinitions;
    }
    
    public void registerFilters() {
        boolean acceptAllInterfaces = true;
        
        if (this.annotationClass != null) {
            addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
            acceptAllInterfaces = false;
        }
        
        if (acceptAllInterfaces) {
            addIncludeFilter(new TypeFilter() {
                @Override
                public boolean match(MetadataReader metadataReader,
                    MetadataReaderFactory metadataReaderFactory) {
                    return true;
                }
            });
        }
        
        // exclude package-info.java
        addExcludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader,
                MetadataReaderFactory metadataReaderFactory)
                throws IOException {
                String className = metadataReader.getClassMetadata()
                    .getClassName();
                return className.endsWith("package-info");
            }
        });
    }
    private void processBeanDefinitions(
        Set<BeanDefinitionHolder> beanDefinitions) {
        
        GenericBeanDefinition definition;
        
        for (BeanDefinitionHolder holder : beanDefinitions) {
            
            definition = (GenericBeanDefinition) holder.getBeanDefinition();
            
            // 将接口的名称添加到构造参数
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
    
//            RpcClient rpcClient = definition.getBeanClass().getAnnotation(RpcClient.class);
//
//            log.error("value is {}, url is {}", rpcClient.value(), rpcClient.url());
            // 设置BeanDefinition的class，借助这个工具类，实现代理rpc调用（底层为netty长连接）
//            definition.setBeanClass(this.rpcFactoryBean.getClass());
            definition.setBeanClass(RpcFactoryBean.class);
    
            
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
            log.info(String.valueOf(holder));
        }
    }
    
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }
}